﻿//  
//  Copyright 2007-2008 Matjaž Mešnjak. All rights reserved.
//  
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//  
//  Redistributions of source code must retain the above copyright
//  notice, this list of conditions and the following disclaimer.
//  
//  Redistributions in binary form must reproduce the above copyright
//  notice, this list of conditions and the following disclaimer in the
//  documentation and/or other materials provided with the distribution.
//  
//  THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
//  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
//  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
//  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//  DAMAGE.
// 
/*
 * Created by SharpDevelop.
 * User: Matjaz
 * Date: 11.11.2007
 * Time: 14:33
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using Microsoft.Win32;

namespace gopher
{
	/// <summary>
	/// Description of Dolpoteg.
	/// </summary>
	public partial class Dolpoteg : Form
	{
		public string mojStreznik;
		public string mojSelektor;
		public string mojaVrata;
		public string mojChecksum;
		private bool plus = false;
		public int myTimeout = 1000;
		string settingsDir = "";
		string errorMessage = "";
		
		public Dolpoteg(string selektor, string streznik, string vrata, string checksum, string settingsdir)
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();

			mojStreznik = streznik;
			mojSelektor = selektor;
			mojaVrata = vrata;
			mojChecksum = checksum;
			settingsDir = settingsdir;
		}
		
		public byte[] PotegniDol()
		{
			List<byte> myFile = new List<byte>();
			try
			{
				TcpClient myClient = new TcpClient();
				myClient.Connect(mojStreznik, Convert.ToInt32(mojaVrata));
				NetworkStream myStream = myClient.GetStream();
				
				String str = mojSelektor+"\r\n";
				ASCIIEncoding asen= new ASCIIEncoding();
				byte[] ba=asen.GetBytes(str);
				myStream.Write(ba,0,ba.Length);
				
				byte[] bb=new byte[1];
				
				int i = 0;
				while(myFile.Count == 0)
				{
					i++;
					if (myStream.DataAvailable == false) Thread.Sleep(myTimeout);
					while (myStream.DataAvailable)
					{
						int k=myStream.Read(bb,0,bb.Length);
						myFile.Add(bb[0]);
						if (myStream.DataAvailable == false) Thread.Sleep(myTimeout);
					}
					if((i == 5) || (myFile.Count != 0))
					{
						break;
					}
					Thread.Sleep(myTimeout);		//
				}
				
				myClient.Close();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
			if(myFile.Count > 0)
			{
				if((plus) && (myFile[0] == Convert.ToInt32('+')))
				{
					myFile.RemoveRange(0,myFile.IndexOf(10)+1);
					//.ToArray().
					return (myFile.ToArray());
				}
				else if((plus) && (myFile[0] == Convert.ToInt32('-')))
				{
					StringBuilder SB = new StringBuilder();
					foreach(byte bajt in myFile)
					{
						SB.Append(Convert.ToChar(bajt));
					}
					errorMessage = SB.ToString();
					errorMessage = errorMessage.Replace("--1", string.Empty);
					errorMessage = errorMessage.Replace("\r\n.\r\n", string.Empty);
					errorMessage = errorMessage.Trim();
					return null;
				}
				else
				{
					return (myFile.ToArray());
				}
			}
			else
			{				
				return null;
			}
		}
		
		bool DownloadAndSave()
		{
			Cursor = System.Windows.Forms.Cursors.WaitCursor;
			System.IO.FileStream fs1=null;
			byte[] b1=null;
			b1 = PotegniDol();
			if(b1 != null)
			{
				try
				{
					fs1=new FileStream(textBox1.Text, FileMode.Create);
					fs1.Write(b1,0,b1.Length);
					fs1.Close();
					fs1 = null;
					// preverimo checksum
					FileInfo FI = new FileInfo(textBox1.Text);
					if((FI.Exists) && (mojChecksum.Length > 0))
					{
						string test = ComputeMD5Digest(FI);
						//MessageBox.Show(test);
						if(mojChecksum.Contains(test))
						{
							return true;
//							MessageBox.Show("Download uspel!");
						}
						else
						{
							if(MessageBox.Show("Download has not succeded! Delete the file?", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.OK)
							{
								FI.Delete();
							}
							return false;
						}
					}
					else
					{
						return true;
					}
				}
				catch(Exception ex)
				{
					MessageBox.Show("Cannot save the file!\n"+ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return false;
				}
			}
			else
			{
				if(errorMessage == string.Empty)
				{
					MessageBox.Show("There was no data recived from the server!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
				}
				else
				{
					MessageBox.Show(errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
				}
				return false;
			}
		}
		
		public static string ComputeMD5Digest(FileInfo fileInfo) {
			FileStream stream = null;
			try {
				stream = File.OpenRead(fileInfo.FullName);
				//if (fileInfo.Extension.ToLower() == ".a78")
				//	stream.Seek(A78HeaderSize, SeekOrigin.Begin);
				return StringifyMD5(new MD5CryptoServiceProvider().ComputeHash(stream));
			}
			finally {
				if (stream != null)
					stream.Close();
			}
		}
		
		private static string StringifyMD5(byte[] bytes) {
			if (bytes.Length != 16) {
				throw new Exception(
					String.Format(
						CultureInfo.InvariantCulture,
						"Wrong MD5 checksum size : {0} bytes",
						bytes.Length
					)
				);
			}
			StringBuilder result = new StringBuilder();
			foreach (byte b in bytes)
				result.AppendFormat("{0:x2}", b);
			return result.ToString();
		}
		
		void Button1Click(object sender, EventArgs e)
		{
			DownloadAndSave();
			Close();
		}

		void Button3Click(object sender, EventArgs e)
		{
			this.Close();
		}
		
		void ResetFolder()
		{
			RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
			textBox1.Text = key.GetValue("Personal").ToString();
		}
		
		void DolpotegLoad(object sender, EventArgs e)
		{
			if(mojSelektor.Contains("\t+")) plus = true;
			string settingsFile;
			RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
			settingsFile = key.GetValue("AppData").ToString()+"\\Gopher\\settings.xml";

			try
			{
				DataSet ds = new DataSet();
				ds.ReadXml(settingsFile);
				DataRow dr = ds.Tables[0].Rows[0];
				textBox1.Text = dr["downloads"].ToString();
				if(textBox1.Text == "")
				{
					ResetFolder();
				}
			}
			catch(Exception)
			{
				ResetFolder();
			}
			string extension = "";
			string imeDatoteke = mojSelektor.Replace("/","\\");
			if(imeDatoteke.Contains("\t"))
			{
				string mime = imeDatoteke.Substring(imeDatoteke.LastIndexOf("+")+1);
				mime = mime.Trim();
				mime = mime.Replace("\\","/");
				if(mime.Contains("_"))
				{
					langLabel.Text = "Language:" + mime.Substring(mime.IndexOf(" "));
				}
				else
				{
					langLabel.Text = "Language: unknown";
				}
				if(mime.Contains(" "))
				{					
					mime = mime.Substring(0, mime.IndexOf(" "));
					mime = mime.ToLower().Trim();
				}
				
				
				mimeLabel.Text = "Mime Type: "+mime;
				extension = GetExtension(mime, settingsDir);
					
				imeDatoteke = imeDatoteke.Substring(0,imeDatoteke.IndexOf("\t"));
				// preveč pameten ... :-)
				if(imeDatoteke.Contains("."))
				{
					if(imeDatoteke.Substring(imeDatoteke.LastIndexOf(".")) != extension)
					{
						if(mime.Length > 0)imeDatoteke = imeDatoteke + extension;
					}
    				//imeDatoteke = imeDatoteke.Substring(0,imeDatoteke.LastIndexOf("."));
				}
				// datoteka nima končnice - dodamo svojo 
				else
				{
					if(mime.Length > 0)imeDatoteke = imeDatoteke + extension;
				}
			}
			if(imeDatoteke.Contains("\\"))
			{
				imeDatoteke = imeDatoteke.Substring(imeDatoteke.LastIndexOf("\\")+1);				
			}
			if(textBox1.Text == "")
			{
				textBox1.Text = Environment.GetEnvironmentVariable("temp");
			}
			textBox1.Text = textBox1.Text+"\\"+imeDatoteke;
		}
		
		void DolpotegHelpRequested(object sender, HelpEventArgs hlpevent)
		{
			Help.ShowHelp(this, Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\"))+"\\Help\\gopher.chm", "html\\download-dialog.htm");
		}
		
		void Button2Click(object sender, EventArgs e)
		{
			if(DownloadAndSave())
			{
				Cursor = System.Windows.Forms.Cursors.Default;
				FileSystemInfo fi = new FileInfo(textBox1.Text);
				if(fi.Exists)
				{
					System.Diagnostics.Process.Start(textBox1.Text);
				}
			}
			this.Close();
		}
		
		private string GetExtension(string sFileMime, string dir)
		{
			StreamReader sr;
			String sLine = "";
			String sMimeType = "";
			//String sFileExt = "";
			String sMimeExt = "";
			
			sMimeExt = ".xxx";
			try
			{
				//Open the Vdirs.dat to find out the list virtual directories
				sr = new StreamReader(dir+"Mime.Dat");
				while ((sLine = sr.ReadLine()) != null)
				{
					
					sLine.Trim();
					if (sLine.Length > 0)
					{
						// Convert to lower case
						sLine = sLine.ToLower();
						sMimeExt = sLine.Substring(0,sLine.IndexOf(";")).Trim();
						sMimeType = sLine.Substring(sLine.IndexOf(";") + 1).Trim();
//MessageBox.Show(sMimeType+"="+sFileMime);
						if (sMimeType == sFileMime)
						{
							
							break;
						}
							
					}
				}
			}
			catch (Exception e)
			{
				MessageBox.Show("An Exception Occurred: " + e.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			return sMimeExt.ToLower().Trim();
			}
		
		
		void BackgroundWorkerDoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
		{
			
		}
	}
}
